import type {
  ComponentRecordType,
  GenerateMenuAndRoutesOptions,
  RouteRecordStringComponent,
} from '@vben/types';

import type { RouteItem } from '#/api/auth';

import { h } from 'vue';

import { generateAccessible } from '@vben/access';

import { ElMessage } from 'element-plus';
import { camelCase, cloneDeep, orderBy, upperFirst } from 'lodash-es';

import { getUserRoute } from '#/api/auth';
import GiSvgIcon from '#/components/gi-svg-icon/index.vue';
import { BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
import { localMenuList } from '#/router/routes/local';

const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');

// 实现 isHttpUrl 函数
const isHttpUrl = (path: string): boolean => {
  try {
    return new URL(path).protocol.startsWith('http');
  } catch {
    return false;
  }
};

// 使用原生 map 实现树形遍历
const mapTree = <T extends { children?: T[] }, R>(
  tree: T[],
  fn: (item: T) => R,
): R[] => {
  return tree.map((item) => {
    const result = fn(item);
    if (item.children?.length) {
      (result as any).children = mapTree(item.children, fn);
    }
    return result;
  });
};

async function generateAccess(options: GenerateMenuAndRoutesOptions) {
  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');

  const layoutMap: ComponentRecordType = {
    BasicLayout,
    IFrameView,
  };
  return await generateAccessible('backend', {
    ...options,
    fetchMenuListAsync: async () => {
      ElMessage({
        duration: 1500,
        message: `${$t('common.loadingMenu')}...`,
      });
      const userRoute = await getUserRoute();
      const formatRouter = formatAsyncRoutes(userRoute);
      return [...cloneDeep(localMenuList), ...formatRouter];
    },
    forbiddenComponent,
    layoutMap,
    pageMap,
  });
}

/**
 * @description 格式化后端返回的路由数据
 */
const formatAsyncRoutes = (
  menus: RouteItem[],
): RouteRecordStringComponent[] => {
  if (menus.length === 0) return [];

  const pathMap = new Map<string, string>();
  return mapTree(menus, (item: RouteItem) => {
    pathMap.set(item.id, item.path);

    if (item.children?.length) {
      // 使用 lodash 的 orderBy 函数进行排序
      item.children = orderBy(item.children, ['sort'], ['asc']);
    }

    const parentPath = item.parentId ? (pathMap.get(item.parentId) ?? '') : '';
    if (item.parentId && item.type === 2 && item.permission) {
      item.activeMenu = parentPath;
    }

    const route: RouteRecordStringComponent = {
      path: item.path,
      name: item.name ?? transformPathToName(item.path),
      component: item.component,
      redirect: item.redirect,
      meta: {
        title: item.title,
        hidden: item.isHidden,
        keepAlive: item.isCache,
        icon: item.icon ? h(GiSvgIcon, { name: item.icon }) : item.icon,
        showInTabs: item.showInTabs,
        activeMenu: item.activeMenu,
      },
    };

    if (item.children) {
      route.children = formatAsyncRoutes(item.children);
    }

    return route;
  });
};

/**
 * @description 使用 lodash 将路由路径转换为名称
 * @example
 * /system => System
 * /system/menu => SystemMenu
 * /data-manage/detail => DataManageDetail
 */
export const transformPathToName = (path: string): string => {
  if (!path) return '';
  if (isHttpUrl(path)) return '';

  // 移除开头的斜杠和结尾的斜杠
  const cleanPath = path.replaceAll(/^\/|\/$/g, '');
  // 转换为帕斯卡命名
  return upperFirst(camelCase(cleanPath)).replaceAll(/\s/g, '');
};

export { generateAccess };
